package com.yanqingshan.platform.module.sys.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yanqingshan.platform.common.constant.AppConstant;
import com.yanqingshan.platform.common.constant.CommonConstant;
import com.yanqingshan.platform.module.sys.mapper.SysResourceMapper;
import com.yanqingshan.platform.module.sys.mapper.SysRoleResourceMapper;
import com.yanqingshan.platform.module.sys.mapper.SysUserRoleMapper;
import com.yanqingshan.platform.module.sys.model.domain.SysResource;
import com.yanqingshan.platform.module.sys.model.domain.SysRoleResource;
import com.yanqingshan.platform.module.sys.model.domain.SysUserRole;
import com.yanqingshan.platform.module.sys.model.vo.CurrentUserInfoRespVO;
import com.yanqingshan.platform.module.sys.model.vo.MenuMetaInfoRespVO;
import com.yanqingshan.platform.module.sys.model.vo.SysResourceRespVO;
import com.yanqingshan.platform.module.sys.service.SysResourceService;
import org.assertj.core.util.Lists;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 功能描述: 系统资源 Service业务层处理
 *
 * @author yanqs
 * @since 2023-05-15
 */
@Service
public class SysResourceServiceImpl extends ServiceImpl<SysResourceMapper, SysResource> implements SysResourceService {

    @Resource
    private SysRoleResourceMapper roleResourceMapper;

    @Resource
    private SysUserRoleMapper userRoleMapper;

    /**
     * 校验资源别名唯一性
     *
     * @param resourceKey 资源key
     * @param id          主键id
     * @return long
     */
    @Override
    public long validateResourceKey(String resourceKey, Long id) {
        long result = this.baseMapper.selectCount(Wrappers.lambdaQuery(SysResource.class).eq(SysResource::getResourceKey, resourceKey));
        if (ObjectUtil.isNotNull(id)) {
            SysResource entity = this.baseMapper.selectById(id);
            if (StrUtil.equalsIgnoreCase(resourceKey, entity.getResourceKey())) {
                return 0;
            }
        }
        return result;
    }

    /**
     * 查询资源树结构信息
     *
     * @return
     */
    @Override
    public List<Tree<Long>> listForManage() {
        List<SysResource> resourceEntities = this.baseMapper.selectList(Wrappers.emptyWrapper());
        TreeNodeConfig config = new TreeNodeConfig();
        List<Tree<Long>> treeNodes = TreeUtil.build(resourceEntities, CommonConstant.ROOT_ID, config, (resourceEntity, treeNode) -> {
            fillTreeNode(treeNode, resourceEntity);
        });
        return treeNodes;
    }

    /**
     * 查询资源树结构信息(角色授权使用)
     *
     * @param roleId
     * @return
     */
    @Override
    public SysResourceRespVO listForGrant(Long roleId) {
        SysResourceRespVO sysResourceRespVO = new SysResourceRespVO();
        List<SysResource> resourceEntities = this.baseMapper.selectList(Wrappers.emptyWrapper());
        TreeNodeConfig config = new TreeNodeConfig();
        List<Tree<Long>> treeNodes = TreeUtil.build(resourceEntities, CommonConstant.ROOT_ID, config, (resourceEntity, treeNode) -> {
            fillSimpleTreeNode(treeNode, resourceEntity);
        });
        sysResourceRespVO.setMenuList(treeNodes);
        List<SysResource> checkedResources = this.listResourceEntitiesByRoleId(roleId);
        List<Long> checkedIds = checkedResources.stream().map(SysResource::getId).collect(Collectors.toList());
        sysResourceRespVO.setCheckedList(checkedIds);
        return sysResourceRespVO;
    }

    @Override
    public List<SysResource> listResourceEntitiesByRoleId(Long roleId) {
        Assert.notNull(roleId, "角色 ID 不能为空");
        List<SysResource> resourceEntities = Lists.newArrayList();
        LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(SysRoleResource.class).eq(SysRoleResource::getRoleId, roleId);
        List<SysRoleResource> entities = roleResourceMapper.selectList(lambdaQueryWrapper);
        List<Long> resourceIds = entities.stream().map(SysRoleResource::getResourceId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(resourceIds)) {
            resourceEntities = this.baseMapper.selectBatchIds(resourceIds);
        }
        return resourceEntities;
    }

    public List<SysResource> listResourceEntitiesByUserId(Long userId) {
        cn.hutool.core.lang.Assert.notNull(userId, "用户 ID 不能为空");
        List<SysResource> resourceEntities = Lists.newArrayList();
        LambdaQueryWrapper lambdaQueryWrapper = Wrappers.lambdaQuery(SysUserRole.class).eq(SysUserRole::getUserId, userId);
        List<SysUserRole> userRoleEntities = userRoleMapper.selectList(lambdaQueryWrapper);
        for (SysUserRole userRoleEntity : userRoleEntities) {
            resourceEntities.addAll(this.listResourceEntitiesByRoleId(userRoleEntity.getRoleId()));
        }
        resourceEntities = resourceEntities.stream().distinct().collect(Collectors.toList());
        return resourceEntities;
    }

    @Override
    public CurrentUserInfoRespVO listForLogin(Long userId) {
        CurrentUserInfoRespVO out = new CurrentUserInfoRespVO();
        List<SysResource> resourceEntities = this.listResourceEntitiesByUserId(userId);
        List<SysResource> menuEntities = Lists.newArrayList();
        menuEntities.addAll(resourceEntities);
        CollectionUtil.filter(menuEntities, e -> !AppConstant.ResourceType.BUTTON.equals(e.getType()));
        TreeNodeConfig config = new TreeNodeConfig();
        List<Tree<Long>> treeNodes = TreeUtil.build(menuEntities, CommonConstant.ROOT_ID, config, (resourceEntity, treeNode) -> {
            fillHomeMenuTreeNode(treeNode, resourceEntity);
        });
        out.setMenu(treeNodes);
        CollectionUtil.filter(resourceEntities, e -> AppConstant.ResourceType.BUTTON.equals(e.getType()));
        List<String> permissions = resourceEntities.stream().map(SysResource::getResourceKey).collect(Collectors.toList());
        out.setPermissions(permissions);
        return out;
    }

    @Override
    public List<Tree<Long>> listAllResourcesByUserId(Long userId) {
        List<SysResource> resourceEntities = this.baseMapper.listAllResourcesByUserId(userId);
        TreeNodeConfig config = new TreeNodeConfig();
        List<Tree<Long>> treeNodes = TreeUtil.build(resourceEntities, CommonConstant.ROOT_ID, config, (resourceEntity, treeNode) -> {
            fillSimpleTreeNode(treeNode, resourceEntity);
        });
        return treeNodes;
    }

    @Override
    public List<String> listAllPermissionsByUserId(Long userId) {
        List<String> keys = this.baseMapper.listAllPermissionsByUserId(userId);
        return keys;
    }


    private void fillTreeNode(Tree<Long> treeNode, SysResource resourceEntity) {
        treeNode.setId(resourceEntity.getId());
        treeNode.setParentId(resourceEntity.getParentId());
        //树形结构构造器的排序字段
        treeNode.setWeight(resourceEntity.getSortNo());
        treeNode.putExtra("type", resourceEntity.getType());
        treeNode.putExtra("title", resourceEntity.getTitle());
        treeNode.putExtra("resourceKey", resourceEntity.getResourceKey());
        treeNode.putExtra("path", resourceEntity.getPath());
        treeNode.putExtra("component", resourceEntity.getComponent());
        treeNode.putExtra("icon", resourceEntity.getIcon());
        treeNode.putExtra("hidden", resourceEntity.getHidden());
        treeNode.putExtra("fullpage", resourceEntity.getFullpage());
        treeNode.putExtra("affix", resourceEntity.getAffix());
        treeNode.putExtra("sortNo", resourceEntity.getSortNo());
        treeNode.putExtra("color", resourceEntity.getColor());
    }

    private void fillSimpleTreeNode(Tree<Long> treeNode, SysResource resourceEntity) {
        treeNode.setId(resourceEntity.getId());
        treeNode.setParentId(resourceEntity.getParentId());
        //树形结构构造器的排序字段
        treeNode.setWeight(resourceEntity.getSortNo());
        treeNode.putExtra("type", resourceEntity.getType());
        treeNode.putExtra("title", resourceEntity.getTitle());
    }

    private void fillHomeMenuTreeNode(Tree<Long> treeNode, SysResource resourceEntity) {
        treeNode.setId(resourceEntity.getId());
        treeNode.setParentId(resourceEntity.getParentId());
        //树形结构构造器的排序字段
        treeNode.setWeight(resourceEntity.getSortNo());
        treeNode.putExtra("name", resourceEntity.getResourceKey());
        treeNode.putExtra("path", resourceEntity.getPath());
        treeNode.putExtra("component", resourceEntity.getComponent());
        MenuMetaInfoRespVO meta = new MenuMetaInfoRespVO();
        meta.setIcon(resourceEntity.getIcon());
        meta.setColor(resourceEntity.getColor());
        meta.setType(resourceEntity.getType());
        meta.setTitle(resourceEntity.getTitle());
        meta.setAffix(BooleanUtil.toBoolean(resourceEntity.getAffix()));
        meta.setFullpage(BooleanUtil.toBoolean(resourceEntity.getFullpage()));
        meta.setHidden(BooleanUtil.toBoolean(resourceEntity.getHidden()));
        treeNode.putExtra("meta", meta);
    }
}
